#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
Simplified BSD License (BSD)
Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this 
      list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#region Record of Change
//             							CHANGE HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | DEVELOPER  | DESCRIPTION                                              |
// -------------------------------------------------------------------------------------
// | 09-Nov-09 | HuyHM      | First creation.                                          |
// -------------------------------------------------------------------------------------
//
#endregion

#region Record of Audit
//             							REVIEW HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | REVIEWER   | NOTES                                                    |
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
//
#endregion

#region Using directives
using System;
using System.ComponentModel;
using System.Drawing;

using Thn;
#endregion

namespace Thn.Interface.Vcl
{
    /// <summary>
    /// Item that can be used in Listbox control.
    /// </summary>
#if DEBUG 
    public
#else
    public
#endif 
    class ListBoxItem
    {
        #region Fields
        /// <summary>
        /// Sub-columns contents.
        /// mContent[0] = column next to title column.
        /// </summary>
        string[] mContents = null;

        /// <summary>
        /// Flag indicate that item has multi-column data.
        /// </summary>
        internal bool IsHasMultiColumn = false;
        #endregion

        #region Properties
        #region Image
        private Image mImage = null;
        /// <summary>
        /// Gets/Sets image icon in beginning of ListboxItem.
        /// </summary>
        [Browsable(true),DefaultValue(null)]
        public Image Image
        {
            get { return mImage; }
            set
            {
                mImage = value;
                NotifyChanged();
            }
        }
        #endregion
        #region Checked
        private bool mChecked = false;
        /// <summary>
        /// Gets/Sets whether this item is checked.
        /// </summary>
        [Browsable(true), DefaultValue (false)]
        public bool Checked
        {
            get { return mChecked; }
            set
            {
                mChecked = value;
                NotifyChanged();
            }
        }
        #endregion
        #region Text
        private string mText = "";
        /// <summary>
        /// Gets/Sets text title for item.
        /// </summary>
        [Browsable(true),DefaultValue("")]
        public string Text
        {
            get { return mText; }
            set
            {
                mText = value;
                NotifyChanged();
            }
        }
        #endregion
        #region Value
        private object mValue = null;
        /// <summary>
        /// Gets/Sets value that attached to this item.
        /// </summary>
        [Browsable(true),DefaultValue(null)]
        public object Value
        {
            get { return mValue; }
            set
            {
                mValue = value;
                NotifyChanged();
            }
        }
        #endregion
        #region Children
        private ListBoxItemList mChildren;
        /// <summary>
        /// Gets/Sets the children items for this item.
        /// </summary>
        [Browsable(true)]
        public ListBoxItemList Children
        {
            get
            {
                if (mChildren == null)
                {
                    mChildren = new ListBoxItemList();
                    mChildren.Parent = this;
                }
                return mChildren;
            }
            set
            {
                // remove parent of current children list
                if (mChildren != null)
                {
                    #region Remove reference
                    mChildren.Parent = null;
                    #endregion
                }
                #region Defensive tracing
                else
                {
                    // keep next step
                }
                #endregion

                // get new value
                mChildren = value;

                if (mChildren!=null)
                {
                    #region Set reference to parent
                    mChildren.Parent = this;
                    #endregion
                }
                #region Defensive tracing
                else
                {
                    // keep silent when children is null
                }
                #endregion

                NotifyChanged();
            }
        }
        #endregion
        #region Is Expanded
        private bool mIsExpanded;
        /// <summary>
        /// Gets/Sets is expanded or not.
        /// </summary>
        public bool IsExpanded
        {
            get { return mIsExpanded; }
            set
            {
                if (mIsExpanded != value)
                {
                    mIsExpanded = value;
                    if ((this.mSiblings != null) && (this.mSiblings.mParentListbox != null))
                    {
                        if (mIsExpanded)
                        {
                            mSiblings.mParentListbox.Expand(this);
                        }
                        else
                        {
                            mSiblings.mParentListbox.Collapse(this);
                        }

                        NotifyChanged();
                    }
                }
                #region Defensive
                else
                {
                    // not notify.
                }
                #endregion
            }
        }
        #endregion

        #region Parent
        /// <summary>
        /// All item that same level.
        /// </summary>
        internal ListBoxItemList mSiblings= null;
        /// <summary>
        /// Gets/Sets parent of current listbox item.
        /// </summary>
        public ListBoxItem Parent
        {
            get
            {
                if (mSiblings != null)
                {
                    return mSiblings.Parent;
                }
                return null;
            }
        }
        #endregion
        #region Tag
        private object mTag;
        /// <summary>
        /// Gets or Sets value which is used for reserved.
        /// </summary>
        public object Tag
        {
            get { return mTag; }
            set { mTag = value; }
        }
        #endregion  
        #endregion

        #region For multi-column

        #region Indexer
        /// <summary>
        /// Gets/Sets item's content based on column index
        /// </summary>
        /// <param name="ColumnIndex">index of column</param>
        public string this[int ColumnIndex]
        {
            get
            {
                return Get(ColumnIndex);
            }
            set
            {
                Set(ColumnIndex, value);
            }
        }
        #endregion

        #region Get/Set value to column
        /// <summary>
        /// Get value at column index.
        /// </summary>
        /// <param name="columnIndex">Column index.</param>
        /// <returns>Text at that column or null when not found.</returns>
        protected string Get(int columnIndex)
        {
            string result = null;
            if (columnIndex == 0)
            {
                result = mText;
            }
            else if (columnIndex > 0) 
            {
                // get from mContent
                if (mContents != null)
                {
                    if (columnIndex <= mContents.Length)
                    {
                        #region When valid column
                        result = mContents[columnIndex - 1];
                        #endregion
                    }
                    #region Defensive tracing
                    else
                    {
                        // not throw exception. keep silent
                    }
                    #endregion
                }
                #region Defensive
                #endregion
            }
            #region Defensive
            else
            {
                throw new IndexOutOfRangeException();
            }
            #endregion

            return result;
        }


        /// <summary>
        /// Set value to a column.
        /// </summary>
        /// <param name="columnIndex">Column Index.</param>
        /// <param name="value">Value.</param>
        protected void Set(int columnIndex, string value)
        {
            if (columnIndex == 0)
            {
                mText = value;
                NotifyChanged();
            }
            else if (columnIndex > 0)
            {
                if (mContents == null)
                {
                    // construct new
                    mContents = new string[columnIndex];
                    mContents[columnIndex - 1] = value;
                }
                else if (columnIndex <= mContents.Length)
                {
                    // when enough space
                    // just assign
                    mContents[columnIndex - 1] = value;
                }
                else
                {
                    // expand it
                    string[] newValue = new string[columnIndex];
                    // copy old value
                    Array.Copy(mContents, newValue, mContents.Length);
                    // assign new value
                    newValue[columnIndex - 1] = value;
                    // assign to mContent again
                    mContents = newValue;
                }

                // ensure the flag
                IsHasMultiColumn = true;

                NotifyChanged();
            }
            #region Defensive
            else
            {
                throw new IndexOutOfRangeException();
            }
            #endregion
        }
        #endregion

        #endregion

        #region Notify change
        /// <summary>
        /// Notify that this item has been changed.
        /// </summary>
        protected void NotifyChanged()
        {
            if ((this.mSiblings != null) && (this.mSiblings.mParentListbox!=null))
            {
                // notify to Listbox.
                this.mSiblings.ParentListBox.NotifyItemModified(this);
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor.
        /// </summary>
        public ListBoxItem() 
        { }

        /// <summary>
        /// Constructor with title text.
        /// </summary>
        /// <param name="text">Title text</param>
        public ListBoxItem(string text)
        {
            mText = text;
        }

        /// <summary>
        /// Constructor with title text and tagged value.
        /// </summary>
        /// <param name="text">Title text.</param>
        /// <param name="tag">Tagged value.</param>
        public ListBoxItem(string text, object tag)
        {
            mText = text;
            mValue = tag;
        }

        /// <summary>
        /// Constructor with title text and flag to show checkbox.
        /// </summary>
        /// <param name="text">Title text.</param>
        /// <param name="isChecked">Whether item is checked.</param>
        public ListBoxItem(string text, bool isChecked)
        {
            mText = text;
            mChecked = isChecked;
        }

        /// <summary>
        /// Constructor with title text, flag to show checkbox and icon image.
        /// </summary>
        public ListBoxItem(string text, bool isChecked, Image image)
        {
            mText = text;
            mChecked = isChecked;
            mImage = image;
        }

        /// <summary>
        /// Constructor with title text, flag to show checkbox and icon image.
        /// </summary>
        public ListBoxItem(string text, bool isChecked, Image image,object value)
        {
            mText = text;
            mChecked = isChecked;
            mImage = image;
            mValue = value;
        }
        #endregion
    }
}
